const getNetTable = array => {
  if (array && array.length) {
    let netArray = new Map();
    for (let i = 0, length = array.length; i < length; i = i + 2) {
      let tempArray = [];
      let [x1, y1] = [array[(i + length - 2) % length], array[(i + length - 1) % length]];
      let [xm, ym] = [array[i], array[i + 1]];
      let [x2, y2] = [array[(i + length + 2) % length], array[(i + length + 3) % length]];
      if (y1 > ym) {
        let deltaX = xm === x1 ? 0 : ((x1 - xm) / (y1 - ym));
        let obj = {
          deltaX,
          yMax: y1,
          xMin: xm
        };
        tempArray.push(obj);
      }
      if (y2 > ym) {
        let deltaX = xm === x2 ? 0 : ((x2 - xm) / (y2 - ym));
        let obj = {
          deltaX,
          yMax: y2,
          xMin: xm
        };
        tempArray.push(obj);
      }
      if (tempArray.length < 1) continue;
      if (netArray.get(ym)) {
        netArray.set(ym, netArray.get(ym).concat(tempArray));
      } else {
        netArray.set(ym, tempArray);
      }
    }
    return netArray;
  }
}

const getAETable = (netTable, yMin, yMax) => {
  if (!netTable) return;
  let aeTable = new Map();
  for (let i = yMin, length = yMax - yMin; i < length; i++) {
    // aeTable[i] = [];
    aeTable.set(i, []);
    if (netTable.get(i)) {
      let netArray = netTable.get(i);
      netArray.forEach(obj => {
        if (obj['yMax'] > i) {
          aeTable.get(i).push({
            deltaX: obj['deltaX'],
            yMax: obj['yMax'],
            x: obj['xMin']
          });
        }
      });
    }
    if (i > yMin) {
      aeTable.get(i - 1).forEach(obj => {
        if (obj['yMax'] > i) {
          aeTable.get(i).push({
            deltaX: obj['deltaX'],
            yMax: obj['yMax'],
            x: obj['x'] + obj['deltaX']
          });
        }
      })
    }
  }
  return aeTable;
}


const getPointsData = data => {
  let [canvasWidth, canvasHeight] = [document.getElementById('webgl').offsetWidth, document.getElementById('webgl').offsetHeight];

  let [webglToPxX, webglToPxY] = [canvasWidth / 2, canvasHeight / 2];

  let [xMin, yMin, xMax, yMax] = [Math.round(data[0] * webglToPxX), Math.round(data[1] * webglToPxY), Math.round(data[0] * webglToPxX), Math.round(data[1] * webglToPxY)];

  let newDataForPX = [];
  for (let i = 0, length = data.length; i < length; i += 2) {
    let [x, y] = [Math.round(data[i] * webglToPxX), Math.round(data[i + 1] * webglToPxY)];
    newDataForPX.push(x, y);
    xMin = xMin > x ? x : xMin;
    yMin = yMin > y ? y : yMin;
    xMax = xMax < x ? x : xMax;
    yMax = yMax < y ? y : yMax;
  }

  let aETable = getAETable(getNetTable(newDataForPX), yMin, yMax);
  let keys = Array.prototype.sort.call(aETable.keys());

  let pointsData = [];
  for (let key of keys) {
    let tempMap = [];
    aETable.get(key).forEach(value => {
      tempMap.push(value['x'] / webglToPxX);
    })
    tempMap.sort();
    for (let i of tempMap) {
      pointsData.push(i, key / webglToPxY);
    }
  }
  return pointsData;
}


(main = () => {
  let VSHADER_SOURCE = ` 
    attribute vec4 a_Position;
    attribute float a_PointSize;
    void main(){
      gl_Position = a_Position;
      gl_PointSize =8.0;
    }`;

  let FSHADER_SOURCE = `
    precision mediump float;
    uniform vec4 u_FragColor;
    void main(){
      gl_FragColor = u_FragColor;
    }`;
  let canvas = document.getElementById('webgl');
  let gl = getWebGLContext(canvas);

  if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
    console.log('Failed to initialize shaders');
    return;
  }

  let a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  let u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor');

  if (a_Position < 0) {
    console.log('failed to get the storage location of a_Position');
    return;
  }
  gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, gl.createBuffer());
  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT);
  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(a_Position);

  // let data = [0.3, 0, 0.3, 0.5, 0, 0.2, -0.3, 0.5, -0.3, 0];
  // let pointsData = getPointsData(data);
  // pointsData.push(...data);
  // gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(pointsData), gl.DYNAMIC_DRAW);
  // gl.uniform4f(u_FragColor, ...[0.0, 0.45, 0.55, 1.0]);
  // gl.drawArrays(gl.LINES, 0, (pointsData.length - data.length) / 2);
  // gl.uniform4f(u_FragColor, ...[1.0, 0.45, 1.0, 1.0]);
  // gl.drawArrays(gl.LINE_LOOP, (pointsData.length - data.length) / 2, data.length / 2);

  // let data = [-0.5189775939262125,
  //   0.34416403513095806,
  //   0.8710998773619358, -0.5012290864137321, -0.6403148175390239, -0.14856748745526738, -0.9934313779555524, -0.1791775061443548,
  //   0.18548196085777824,
  //   0.883532955347164
  // ];
  let data = []
  for (let j = 0; j < 10; j++) {
    if (Math.random() < 0.5) {
      data.push((-1) * Math.random());
    } else {
      data.push(Math.random());
    }
  }
  pointsData = getPointsData(data);
  pointsData.push(...data);

  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(pointsData), gl.DYNAMIC_DRAW);

  gl.uniform4f(u_FragColor, ...[0.0, 0.1, 1.0, 1.0]);
  gl.drawArrays(gl.LINES, 0, (pointsData.length - data.length) / 2);
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([0, 1, 2, 3]), gl.DYNAMIC_DRAW);
  // gl.uniform4f(u_FragColor, ...[1.0, 0.0, 0.0, 1.0]);
  // gl.drawArrays(gl.POINTS, 0, (pointsData.length - data.length) / 2);
  // gl.uniform4f(u_FragColor, ...[0.0, 1.0, 0.0, 1.0]);
  // gl.drawArrays(gl.POINTS, (pointsData.length - data.length) / 2, data.length / 2);
  // gl.drawArrays(gl.LINE_STRIP, (pointsData.length - data.length) / 2, data.length / 2);
})();